
#include <BQuad>
#include <BRender>
#include <BViewer>
#include <BMesh>
#include <BCamera>
#include <BLight>
#include <BState>
#include <BSphere>
#include <BSurface>
#include <BGeometry>
#include <BSphereControl>
#include <BScene>
#include <BCylinder>

#include <BIcon>
#include <BReadWrite>
#include <BTexture>
#include <BImage>
#include <BMotion>
#include <BMaterial>

#include <BGridLayout>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BButton>
#include <BComboBox>
#include <BMainWindow>
#include <BApplication>

using namespace BWE;

class MotionNode : public BNode
{
public:
	MotionNode()
	{
		_motion = new BMotion;
		_motion->setDuration(3);
		_motion->setStartValue(0);

		_points;
		_points[0].set(-3, -3, 3);
		_points[1].set(3, -3, 3);
		_points[2].set(3, 3, 3);
		_points[3].set(-3, 3, 3);

		BPlane topPlane(_points[0], _points[1], _points[2]);
		BPlane planes[4];
		planes[0].set(_points[0], _points[1], BVector(0, 0, 0));
		planes[1].set(_points[1], _points[2], BVector(0, 0, 0));
		planes[2].set(_points[2], _points[3], BVector(0, 0, 0));
		planes[3].set(_points[3], _points[0], BVector(0, 0, 0));

		BVector p0 = intersect(topPlane, planes[0], planes[1]);
		BVector p1 = intersect(topPlane, planes[1], planes[2]);
		BVector p2 = intersect(topPlane, planes[2], planes[3]);
		BVector p3 = intersect(topPlane, planes[3], planes[0]);

		_quad.set(p0, p1, p2, p3);
	}
	~MotionNode()
	{

	}

	void setMotion(BMotion* motion)
	{
		_motion = motion;
	}
	BMotion* motion()
	{
		return _motion;
	}

protected:
	virtual void update(const BEvent& event)
	{
		if (_motion)
		{
			double time = event.time();
			_motion->update(time);
			float x = _motion->value() * 10;
			BVector pos = this->position();
			pos.x() = x;
			this->setPosition(pos);
		}
	}
	virtual void render0(BRender& render)
	{
		render.setLighting(false);

		render.setColor(255, 255, 0);
		render.drawQuad(_quad);

		render.setPointSize(5);
		render.setPointSmooth(true);
		render.setColor(255, 0, 0);
		render.drawPoints(_points, 4);

		render.setLighting(true);
	}

private:
	BVector				_points[4];
	BQuad				_quad;
	BMotionHolder		_motion;
};

class MainWindow : public BMainWindow
{
public:
	MainWindow()
	{
		BScene* scene = new BScene();

		BCamera* camera = new BCamera();
		camera->setPosition(0, -16, 0);
		camera->setCenter(0, 0, 0);
		camera->project(36.0, 0.1, 1000);

		_viewer = new BViewer();
		_viewer->setScene(scene);
		_viewer->setCamera(camera);
		_viewer->setControl(new BSphereControl());

		BImage* image = Read<BImage>("./data/image/neon_013.png");
		_resetButton = new BButton(image, "reset");
		_playButton = new BButton("play");
		_pauseButton = new BButton("pause");
		_comboBox = new BComboBox();
		_comboBox->addItem("None");
		_comboBox->addItem("Linear");
		_comboBox->addItem("OutBounce");
		_comboBox->addItem("InBounce");
		_comboBox->addItem("InOutBounce");
		_comboBox->addItem("OutQuad");
		_comboBox->addItem("InQuad");
		_comboBox->addItem("InOutQuad");
		_comboBox->addItem("OutCubic");
		_comboBox->addItem("InCubic");
		_comboBox->addItem("InOutCubic");
		_comboBox->addItem("InQuart");
		_comboBox->addItem("OutQuart");
		_comboBox->addItem("InOutQuart");
		_comboBox->addItem("OutElastic");
		_comboBox->addItem("InElastic");
		_comboBox->addItem("InOutElastic");
		_comboBox->addItem("OutSine");
		_comboBox->addItem("InSine");
		_comboBox->addItem("InOutSine");
		_comboBox->addItem("OutBack");
		_comboBox->addItem("InBack");
		_comboBox->addItem("InOutBack");
		_comboBox->addItem("OutCirc");
		_comboBox->addItem("InCirc");
		_comboBox->addItem("InOutCirc");
		_comboBox->addItem("OutExpo");
		_comboBox->addItem("InExpo");
		_comboBox->addItem("InOutExpo");
		_comboBox->setCurrent(0);

		BHBoxLayout* hlayout = new BHBoxLayout();
		hlayout->addWidget(_resetButton);
		hlayout->addWidget(_playButton);
		hlayout->addWidget(_pauseButton);
		hlayout->addWidget(_comboBox);

		BVBoxLayout* layout = new BVBoxLayout(this);
		layout->addLayout(hlayout);
		layout->addWidget(_viewer);

		connect(_resetButton, Signal_Clicked, &MainWindow::procReset);
		connect(_playButton, Signal_Clicked, &MainWindow::procPlay);
		connect(_pauseButton, Signal_Clicked, &MainWindow::procPause);
		connect(_comboBox, Signal_CurrentChanged, &MainWindow::procCurrentChanged);
	}

	void setMotionNode(MotionNode* motionNode)
	{
		_motion = motionNode->motion();
		_viewer->scene()->addNode(motionNode);
	}
	BMotion* motion()
	{
		return _motion;
	}

protected:
	void procCurrentChanged(BObject* object, const BValue& value)
	{
		MotionType type = (MotionType)_comboBox->current();
		_motion->setType(type);
	}
	void procPlay(BObject* object, const BValue& value)
	{
		_motion->start();
	}
	void procReset(BObject* object, const BValue& value)
	{
		_motion->reset();
	}
	void procPause(BObject* object, const BValue& value)
	{
		_motion->pause();
	}

protected:
	virtual void updateEvent(const BEvent& event)
	{
		if (_motion && _motion->started())
		{
			_viewer->fresh();
		}
	}

private:
	BViewer*			_viewer;
	BButtonHolder		_resetButton;
	BButtonHolder		_playButton;
	BButtonHolder		_pauseButton;
	BComboBoxHolder		_comboBox;
	BMotionHolder		_motion;
};

MotionNode* createSphere()
{
	BMaterial* material = new BMaterial();

	BSphere* sphere = new BSphere(1, 12, 12);
	sphere->setColor(255, 0, 0);
	sphere->setMaterial(material);

	BState* state = new BState();
	state->setLighting(true);
	MotionNode* node = new MotionNode();
	node->addShape(sphere);
	node->setState(state);

	return node;
}

BShape* createGround()
{
	BSurface* surface = new BSurface(10, 10, 10, 10);
	surface->setOrigin(BVector(-5, -5, 0));

	return surface;
}

int main(int argc, char** argv)
{
	BApplication app;

	MotionNode* node = createSphere();

	BIcon* icon = new BIcon("data/ui/motion.png");
	MainWindow mw;
	mw.setTitle("Motion");
	mw.setTitleIcon(icon);
	mw.setFont("times");
	mw.show();
	mw.setMotionNode(node);

	return app.execute();
}